﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.WeChat.Configurations;
using NewRetail.Application.Components.WeChat.Model;
using NewRetail.Application.Components.WeChat.Services.HttpClients;
using NewRetail.Application.Utility;
using SKIT.FlurlHttpClient.Wechat.Api;
using SKIT.FlurlHttpClient.Wechat.Api.Events;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace NewRetail.Application.Components.WeChat.Services
{
    #region 微信网页授权消息接口
    /// <summary>
    /// 微信网页授权消息接口
    /// </summary>
    public interface IWeChatOAuth2Service : IApplicationService
    {
        /// <summary>
        /// 微信授权返回URL地址。
        /// </summary>
        /// <param name="url">前端需要跳转的页面地址</param>
        /// <returns></returns>
        (string, string) GetWeChatOAuthUrl(string redirectUrl, string appId = null);

        /// <summary>
        /// 根据code获取openid等信息
        /// </summary>
        /// <param name="queryString"></param>
        /// <param name="code"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<(WeChatOAuth2UserInfoDto, string)> GetWeChatUserByCode(QueryString queryString, string code = null, string appId = null);
        /// <summary>
        /// 获取微信配置供前端JS-SDK调用使用
        /// </summary>
        /// <param name="url"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<(WeChatConfigJsSdkInfoDto, string)> GetWechatConfigInfo(string url, string appId = null);
    }
    #endregion

    #region 微信网页授权实现
    public class WeChatOAuth2Service : ApplicationService, IWeChatOAuth2Service
    {
        #region Field
        private readonly IWeChatApiHttpClientFactory _wechatApiHttpClientFactory;        
        private readonly ILogger _logger;
        private readonly WeChatOptions _wechatOptions;
        private readonly IHttpContextAccessor _accessor;
        private readonly IWeChatAccessToken _weChatAccessToken;
        #endregion

        #region 构造函数
        public WeChatOAuth2Service(IHttpContextAccessor accessor, IWeChatApiHttpClientFactory wechatApiHttpClientFactory,
            IWeChatAccessToken weChatAccessToken, IOptions<WeChatOptions> wechatOptions, ILogger<WeChatOAuth2Service> logger)
        {
            _wechatApiHttpClientFactory = wechatApiHttpClientFactory;
            _logger = logger;
            _wechatOptions = wechatOptions.Value;
            _accessor = accessor;
            _weChatAccessToken = weChatAccessToken;
        }
        #endregion

        #region Implementation of ISignatureService

        #region 微信授权返回URL地址
        /// <summary>
        /// 微信授权返回URL地址。
        /// </summary>
        /// <param name="redirectUrl">前端需要跳转的页面地址</param>
        /// <returns></returns>
        public (string, string) GetWeChatOAuthUrl(string redirectUrl, string appId = null)
        {
            string retUri = "", errMsg = "";
            try
            {
                //如果appId为空，那么就直接获取默认第一个
                if (string.IsNullOrEmpty(appId))
                    appId = _wechatOptions.Accounts?.FirstOrDefault().AppId;
                string state = redirectUrl.ToMd5();
                //使用微信接口，重定向地址为本接口中的另一方法  此地址域名需要加在微信公众号网页授权里面
                retUri = string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_base&state={2}#wechat_redirect", appId, redirectUrl, state);
            }
            catch (Exception e)
            {
                _logger.LogError(message: e.Message, exception: e);
                errMsg = e.Message;
            }
            return (retUri, errMsg);
        }
        #endregion

        #region 根据code获取openid等信息
        /// <summary>
        /// 根据code获取openid等信息
        /// </summary>
        /// <param name="queryString"></param>
        /// <param name="code"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<(WeChatOAuth2UserInfoDto, string)> GetWeChatUserByCode(QueryString queryString, string code = null, string appId = null)
        {
            var weChatOAuth2UserInfo = new WeChatOAuth2UserInfoDto();
            var errMsg = "";
            IDictionary<string, string> parameters = new Dictionary<string, string>();
            try
            {
                if (queryString.HasValue)
                {
                    var parms = string.Join("&", queryString.Value.TrimStart('?').Split('&').Select(s =>
                    {
                        var kv = s.Split('=');
                        var k = kv[0].Replace("_", "");
                        var v = kv[1];
                        return $"{k}={v}";
                    }));

                    var queryList = parms.Split("&");
                    foreach (string key in queryList)
                    {
                        if (!string.IsNullOrEmpty(key))
                        {
                            parameters.Add(key.Split("=")[0].ToString(), key.Split("=")[1].ToString());
                        }
                    }
                    if (parameters.ContainsKey("code"))
                    {
                        code = parameters["code"].ToString();
                    }
                }

                if (!string.IsNullOrEmpty(code))
                {
                    //如果appId为空，那么就直接获取默认第一个
                    if (string.IsNullOrEmpty(appId))
                        appId = _wechatOptions.Accounts?.FirstOrDefault().AppId;
                    //创建一个http
                    var wechatApiclient = _wechatApiHttpClientFactory.Create(appId);
                    var requestInfo = new SnsOAuth2AccessTokenRequest()
                    {
                        Code = code                        
                    };
                    //请求获取数据
                    var responseOAuthTokenInfo = await wechatApiclient.ExecuteSnsOAuth2AccessTokenAsync(requestInfo);
                    if (!responseOAuthTokenInfo.IsSuccessful())
                    {
                        _logger.LogWarning(
                            "获取网页授权access_token失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                            responseOAuthTokenInfo.RawStatus, responseOAuthTokenInfo.ErrorCode, responseOAuthTokenInfo.ErrorMessage
                        );
                        errMsg = responseOAuthTokenInfo.ErrorMessage;
                        return (weChatOAuth2UserInfo, errMsg);
                    }
                    if (responseOAuthTokenInfo != null && !string.IsNullOrEmpty(responseOAuthTokenInfo.OpenId))
                    {
                        string accessToken = string.Empty;
                        //请求获取AccessToken数据,由于不能频繁请求，所以这边从redis里面获取
                        //var requestAccessTokenInfo = new CgibinTokenRequest();
                        //var responseAccessTokenInfo = await wechatApiclient.ExecuteCgibinTokenAsync(requestAccessTokenInfo, cancellationToken: _accessor.HttpContext.RequestAborted);
                        var responseAccessTokenInfo = await _weChatAccessToken.GetAccessTokenObject(appId);

                        if (responseAccessTokenInfo != null && !string.IsNullOrEmpty(responseAccessTokenInfo.AccessToken))
                        {
                            accessToken = responseAccessTokenInfo.AccessToken;
                        }

                        var openId = responseOAuthTokenInfo.OpenId;
                        ////获取用户详细信息
                        //var requestUserInfo = new CgibinUserInfoRequest() { AccessToken = accessToken, OpenId = openId };
                        //var resultUserInfo = await wechatApiclient.ExecuteCgibinUserInfoAsync(requestUserInfo, cancellationToken: _accessor.HttpContext.RequestAborted);
                        //if (!resultUserInfo.IsSuccessful())
                        //{
                        //    _logger.LogWarning(
                        //        "获取用户信息失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                        //        resultUserInfo.RawStatus, resultUserInfo.ErrorCode, resultUserInfo.ErrorMessage
                        //    );
                        //}
                        weChatOAuth2UserInfo.OpenId = openId;
                    }
                    else
                    {
                        errMsg = "获取用户信息失败!";
                    }
                }
                else
                {
                    errMsg = "code不能为空！";
                }
            }
            catch(Exception e)
            {
                _logger.LogError("获取用户信息异常：" + e.Message);
                errMsg = "获取用户信息失败!" + e.Message;
            }
            return (weChatOAuth2UserInfo, errMsg);
        }
        #endregion

        #region 获取微信配置供前端JS-SDK调用使用
        /// <summary>
        /// 获取微信配置供前端JS-SDK调用使用
        /// </summary>
        /// <param name="url"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<(WeChatConfigJsSdkInfoDto, string)> GetWechatConfigInfo(string url, string appId = null)
        {
            var weChatConfigJsSdkInfoDto = new WeChatConfigJsSdkInfoDto();
            var errMsg = "";
            try
            {
                if (!string.IsNullOrEmpty(url))
                {
                    //如果appId为空，那么就直接获取默认第一个
                    if (string.IsNullOrEmpty(appId))
                        appId = _wechatOptions.Accounts?.FirstOrDefault().AppId;
                    //创建一个http
                    var wechatApiclient = _wechatApiHttpClientFactory.Create(appId);
                    
                    string accessToken = string.Empty;
                    //1、请求获取AccessToken数据,由于不能频繁请求，所以这边从redis里面获取
                    //var requestAccessTokenInfo = new CgibinTokenRequest();
                    //var responseAccessTokenInfo = await wechatApiclient.ExecuteCgibinTokenAsync(requestAccessTokenInfo, cancellationToken: _accessor.HttpContext.RequestAborted);
                    var responseAccessTokenInfo = await _weChatAccessToken.GetAccessTokenObject(appId);
                    if (responseAccessTokenInfo != null && !string.IsNullOrEmpty(responseAccessTokenInfo.AccessToken))
                    {
                        accessToken = responseAccessTokenInfo.AccessToken;
                    }
                    //2、获取Ticket
                    string jsapiTicket = await getJsapiTicket(accessToken, wechatApiclient);
                    //3、获取返回的配置结果
                    var paramConfig = wechatApiclient.GenerateParametersForJSSDKConfig(jsapiTicket, url);
                    if (paramConfig != null)
                    {
                        weChatConfigJsSdkInfoDto.appId = appId;
                        weChatConfigJsSdkInfoDto.nonceStr= paramConfig["nonceStr"];
                        weChatConfigJsSdkInfoDto.timestamp = paramConfig["timestamp"];
                        weChatConfigJsSdkInfoDto.signature= paramConfig["signature"];
                        weChatConfigJsSdkInfoDto.url = url;
                        weChatConfigJsSdkInfoDto.jsapiTicket = jsapiTicket;
                    }                            
                    else
                    {
                        errMsg = "获取返回的配置结果失败！";
                    }
                }
                else
                {
                    errMsg = "url不能为空！";
                }
            }
            catch (Exception e)
            {
                _logger.LogError("获取结果异常：" + e.Message);
                errMsg = "获取结果失败!" + e.Message;
            }
            return (weChatConfigJsSdkInfoDto, errMsg);
        }
        #endregion

        #endregion

        #region private method

        #region 获取微信jsapi_ticket
        private async Task<string> getJsapiTicket(string accessToken, WechatApiClient wechatApiclient)
        {
            var ticket = "";
            var requestAccessTokenInfo = new CgibinTicketGetTicketRequest()
            {
                AccessToken = accessToken
            };
            var responseTicketInfo = await wechatApiclient.ExecuteCgibinTicketGetTicketAsync(requestAccessTokenInfo, cancellationToken: _accessor.HttpContext.RequestAborted);
            if (!responseTicketInfo.IsSuccessful())
            {
                _logger.LogWarning(
                    "获取获取微信jsapi_ticket失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    responseTicketInfo.RawStatus, responseTicketInfo.ErrorCode, responseTicketInfo.ErrorMessage
                );
            }
            else
                ticket = responseTicketInfo.Ticket;
            return ticket;
        }
        #endregion

        #endregion
    }
    #endregion
}
